/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package j3dscene.models;

import com.sun.j3d.loaders.Scene;
import com.sun.j3d.utils.image.TextureLoader;
import idk.IDK;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import j3dscene.PrioUserData;
import javax.media.j3d.*;
import javax.swing.JFrame;
import javax.vecmath.Color4f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import org.jdesktop.j3d.loaders.vrml97.VrmlLoader;

/**
 * Creates a branchgroup of drums which are created in Cinema4D and where
 * exported as a VRML97 compatible file.
 *
 * @author Dominik K.
 * @author Steffen G.
 */
public class Drums {

    /**
     * Contains all the transformgroups/nodes of the vrml object.
     */
    private BranchGroup sceneGroup;
    
    /**
     * the scene file contains all kind of information about the vrml object.
     */
    private Scene scene;
    
    /**
     * Loader for creating an scene object from a .wrl file.
     */
    private VrmlLoader vrmlLoader;
    
    /**
     * Contains all the object pickable by their name.
     */
    private Hashtable transformGroups;
    
    

    /**
     * Loads the .wrl file, sets userdata and capabilities to every
     * transformgroup existing in the scenegroup.
     * @param wrlPath 
     */
    public Drums(java.net.URL wrlPath) {
        this.vrmlLoader = new VrmlLoader();
        System.out.println("Loading Scene from File: " + wrlPath);

        try {
            this.scene = vrmlLoader.load(wrlPath);
        } catch (Exception e) {
            System.out.println("Could not load Scene by File " + wrlPath);
        }

        /*
         * Setting the ALLOW_DETACH capability on the sceneGroup to detach this
         * BG from the objectroot to append an interpolator object which is
         * neccessary for animation
         */
        this.sceneGroup = scene.getSceneGroup();
        this.sceneGroup.setCapability(BranchGroup.ALLOW_DETACH);

        /*
         * setting the ALLOW_TRANSFROM_WRITE on all TGs in wrl file also create
         * userdata for each TG
         */
        transformGroups = scene.getNamedObjects();
        Iterator it = transformGroups.keySet().iterator();
        HashMap<String, Integer> importantObjects = createPrioImportantObjects();

        while (it.hasNext()) {
            String key = (String) it.next();
            TransformGroup actTG = (TransformGroup) transformGroups.get(key);

            /*
             * set userdata (for picking)
             */
            PrioUserData actUserData = new PrioUserData();
            Integer val = importantObjects.get(key);
            if (val != null) {
                actUserData.setPriority(val);
            } else {
                actUserData.setPriority(99);
            }
            actUserData.setName((String) key);
            actTG.getChild(0).setUserData(actUserData);

            /*
             * set capability (for interaction and animation)
             */
            actTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            
        }
        //setCymbalTextures();
    }
    
    

    /**
     * Creates the list of important pickobjects in the scenegroup.
     * @return List of important objects by their name and priority.
     */
    private HashMap<String, Integer> createPrioImportantObjects() {
        HashMap<String, Integer> importantObjects =
                new HashMap<String, Integer>();
        importantObjects.put("SnareFell", 15);
        importantObjects.put("SnareBody", 5);
        importantObjects.put("BassdrumSchlagfell", 5);
        importantObjects.put("BassdrumResonanzfell", 20);
        importantObjects.put("BassBody", 15);
        importantObjects.put("FussmaschinePedal", 3);
        importantObjects.put("FussmaschineGrundplatte", 13);
        importantObjects.put("FloorTomBody", 5);
        importantObjects.put("FloortomFell", 10);
        importantObjects.put("RacktomBody", 8);
        importantObjects.put("RacktomFell", 10);
        importantObjects.put("HiHatTopCymbal", 5);
        importantObjects.put("HiHatBottomCymbal", 40);
        importantObjects.put("HiHatPedal", 1);
        importantObjects.put("RideCymbal", 2);
        importantObjects.put("RideStativ", 45);
        importantObjects.put("CrashCymbal", 2);
        importantObjects.put("HockerSitz", 1);
        importantObjects.put("HockerStativ", 10);

        return importantObjects;
    }
    
    

    /**
     * Animates the Pedalmovement
     */
    public void animatePedal() {

        BoundingSphere view = new BoundingSphere();

        TransformGroup pedal =
                (TransformGroup) getTransformGroups().get("FussmaschinePedal");
        TransformGroup schlaegel =
                (TransformGroup) getTransformGroups().get("FussmaschineSchlaegelAchse");
        
        Alpha pedalAlphaDown = new Alpha(1, 100);
        Alpha pedalAlphaUp = new Alpha(1, 100);
        pedalAlphaDown.setTriggerTime(0);
        pedalAlphaDown.setStartTime(System.currentTimeMillis()
                - pedalAlphaDown.getTriggerTime());
        pedalAlphaUp.setTriggerTime(100);
        pedalAlphaUp.setStartTime(System.currentTimeMillis()
                - pedalAlphaDown.getTriggerTime());

        RotationInterpolator pedalRotationDown =
                new RotationInterpolator(pedalAlphaDown, pedal);
        pedalRotationDown.setSchedulingBounds(view);
        Transform3D rotate = new Transform3D();
        rotate.rotZ(Math.PI / 2);
        pedalRotationDown.setTransformAxis(rotate);
        pedalRotationDown.setMinimumAngle((float) Math.toRadians(-15));
        pedalRotationDown.setMaximumAngle((float) Math.toRadians(-7));
        getSceneGroup().addChild(pedalRotationDown);

        RotationInterpolator pedalRotationUp =
                new RotationInterpolator(pedalAlphaUp, pedal);
        pedalRotationUp.setSchedulingBounds(view);
        pedalRotationUp.setTransformAxis(rotate);
        pedalRotationUp.setMinimumAngle((float) Math.toRadians(-7));
        pedalRotationUp.setMaximumAngle((float) Math.toRadians(-15));
        getSceneGroup().addChild(pedalRotationUp);

        Alpha schlaegelAlphaDown = new Alpha(1, 100);
        Alpha schlaegelAlphaUp = new Alpha(1, 100);
        schlaegelAlphaDown.setTriggerTime(0);
        schlaegelAlphaDown.setStartTime(System.currentTimeMillis()
                - schlaegelAlphaDown.getTriggerTime());
        schlaegelAlphaUp.setTriggerTime(100);
        schlaegelAlphaUp.setStartTime(System.currentTimeMillis()
                - schlaegelAlphaDown.getTriggerTime());

        RotationInterpolator schlaegelRotationDown =
                new RotationInterpolator(schlaegelAlphaDown, schlaegel);
        schlaegelRotationDown.setSchedulingBounds(view);

        Transform3D rotateSchlaegel = new Transform3D();
        rotateSchlaegel.rotZ(Math.PI / 2);
        schlaegelRotationDown.setTransformAxis(rotate);
        schlaegelRotationDown.setMinimumAngle((float) Math.toRadians(-15));
        schlaegelRotationDown.setMaximumAngle((float) Math.toRadians(35));
        getSceneGroup().addChild(schlaegelRotationDown);

        RotationInterpolator schlaegelRotationUp =
                new RotationInterpolator(schlaegelAlphaUp, schlaegel);
        schlaegelRotationUp.setSchedulingBounds(view);

        schlaegelRotationUp.setTransformAxis(rotate);
        schlaegelRotationUp.setMinimumAngle((float) Math.toRadians(35));
        schlaegelRotationUp.setMaximumAngle((float) Math.toRadians(-15));
        getSceneGroup().addChild(schlaegelRotationUp);


    }

    /**
     * Animates the hihat movement.
     */
    public void animateHihat() {

        BoundingSphere view = new BoundingSphere();

        TransformGroup pedal =
                (TransformGroup) getTransformGroups().get("HiHatPedal");
        TransformGroup bottom =
                (TransformGroup) getTransformGroups().get("HihatBewStangeUnten");
        TransformGroup top =
                (TransformGroup) getTransformGroups().get("HihatBewOben");

        Alpha pedalAlphaDown = new Alpha(1, 150);
        Alpha pedalAlphaUp = new Alpha(1, 150);
        pedalAlphaDown.setTriggerTime(0);
        pedalAlphaDown.setStartTime(System.currentTimeMillis()
                - pedalAlphaDown.getTriggerTime());
        pedalAlphaUp.setTriggerTime(150);
        pedalAlphaUp.setStartTime(System.currentTimeMillis()
                - pedalAlphaDown.getTriggerTime());

        Transform3D rotate = new Transform3D();
        rotate.rotZ(Math.PI / 2);

        RotationInterpolator pedalRotationDown =
                new RotationInterpolator(pedalAlphaDown, pedal);
        pedalRotationDown.setSchedulingBounds(view);
        pedalRotationDown.setTransformAxis(rotate);
        pedalRotationDown.setMinimumAngle((float) Math.toRadians(-14));
        pedalRotationDown.setMaximumAngle((float) Math.toRadians(-7));

        RotationInterpolator pedalRotationUp =
                new RotationInterpolator(pedalAlphaUp, pedal);
        pedalRotationUp.setSchedulingBounds(view);
        pedalRotationUp.setTransformAxis(rotate);
        pedalRotationUp.setMinimumAngle((float) Math.toRadians(-7));
        pedalRotationUp.setMaximumAngle((float) Math.toRadians(-14));

        getSceneGroup().addChild(pedalRotationDown);
        getSceneGroup().addChild(pedalRotationUp);

        Alpha positionAlphaLowDown = new Alpha(1, 150);
        Alpha positionAlphaLowUp = new Alpha(1, 150);
        positionAlphaLowDown.setTriggerTime(0);
        positionAlphaLowDown.setStartTime(System.currentTimeMillis()
                - positionAlphaLowDown.getTriggerTime());
        positionAlphaLowUp.setTriggerTime(150);
        positionAlphaLowUp.setStartTime(System.currentTimeMillis()
                - positionAlphaLowDown.getTriggerTime());

        Transform3D axis = new Transform3D();
        axis.set(new Vector3d(0, 1, 0));
        float[] animKnots = {0.0f, 1.0f};

        Point3f[] p3fdown = {new Point3f(0.0f, 0.0f, 0.0f),
            new Point3f(0.0f, -0.015f, 0.0f)};
        PositionPathInterpolator lowMoveDown =
                new PositionPathInterpolator(positionAlphaLowDown, bottom, axis,
                animKnots, p3fdown);
        lowMoveDown.setSchedulingBounds(view);

        Point3f[] p3fup = {new Point3f(0.0f, -0.015f, 0.0f),
            new Point3f(0.0f, 0.0f, 0.0f)};
        PositionPathInterpolator lowMoveUp =
                new PositionPathInterpolator(positionAlphaLowUp, bottom, axis,
                animKnots, p3fup);
        lowMoveUp.setSchedulingBounds(view);

        Alpha positionAlphaTopDown = new Alpha(1, 150);
        Alpha positionAlphaTopUp = new Alpha(1, 150);
        positionAlphaTopDown.setTriggerTime(0);
        positionAlphaTopDown.setStartTime(System.currentTimeMillis()
                - positionAlphaTopDown.getTriggerTime());
        positionAlphaTopUp.setTriggerTime(150);
        positionAlphaTopUp.setStartTime(System.currentTimeMillis()
                - positionAlphaTopDown.getTriggerTime());

        Point3f[] p3fdownTop = {new Point3f(0.0f, 0.0f, 0.0f),
            new Point3f(0.0f, -0.01f, 0.0f)};
        PositionPathInterpolator topMoveDown =
                new PositionPathInterpolator(positionAlphaTopDown, top, axis,
                animKnots, p3fdownTop);
        topMoveDown.setSchedulingBounds(view);

        Point3f[] p3fupTop = {new Point3f(0.0f, -0.01f, 0.0f),
            new Point3f(0.0f, 0.0f, 0.0f)};
        PositionPathInterpolator topMoveUp =
                new PositionPathInterpolator(positionAlphaTopUp, top, axis,
                animKnots, p3fupTop);
        topMoveUp.setSchedulingBounds(view);

        getSceneGroup().addChild(lowMoveDown);
        getSceneGroup().addChild(lowMoveUp);
        getSceneGroup().addChild(topMoveDown);
        getSceneGroup().addChild(topMoveUp);
    }

    /**
     * Animates the crash- or ride cymbal movement
     * @param cymbalName Crash- or ride cymbal.
     */
    public void animateCymbals(String cymbalName) {
        BoundingSphere view = new BoundingSphere();

        TransformGroup cymbal = new TransformGroup();
        if (cymbalName.equals("RideCymbal")) {
            cymbal = (TransformGroup) getTransformGroups().get("RideCymbal");
        } else if (cymbalName.equals("CrashCymbal")) {
            cymbal = (TransformGroup) getTransformGroups().get("CrashCymbal");
        } else if (cymbalName.equals("HihatOpen")) {
            cymbal = (TransformGroup) getTransformGroups().get("HiHatTopCymbal");
        }

        Alpha alphaOne = new Alpha(8, 50);
        Alpha alphaTwo = new Alpha(8, 50);
        Alpha alphaThree = new Alpha(8, 50);
        Alpha alphaFour = new Alpha(8, 50);
        alphaOne.setTriggerTime(0);
        alphaOne.setAlphaAtOneDuration(150);
        alphaOne.setStartTime(System.currentTimeMillis()
                - alphaOne.getTriggerTime());
        alphaTwo.setTriggerTime(50);
        alphaTwo.setAlphaAtOneDuration(150);
        alphaTwo.setStartTime(System.currentTimeMillis()
                - alphaOne.getTriggerTime());
        alphaThree.setTriggerTime(100);
        alphaThree.setAlphaAtOneDuration(150);
        alphaThree.setStartTime(System.currentTimeMillis()
                - alphaOne.getTriggerTime());
        alphaFour.setTriggerTime(150);
        alphaFour.setAlphaAtOneDuration(150);
        alphaFour.setStartTime(System.currentTimeMillis()
                - alphaOne.getTriggerTime());

        Transform3D rotate = new Transform3D();
        rotate.rotZ(Math.PI / 2);

        RotationInterpolator rotationOne =
                new RotationInterpolator(alphaOne, cymbal);
        rotationOne.setSchedulingBounds(view);
        rotationOne.setTransformAxis(rotate);
        rotationOne.setMinimumAngle((float) Math.toRadians(0));
        rotationOne.setMaximumAngle((float) Math.toRadians(-15));
        getSceneGroup().addChild(rotationOne);

        RotationInterpolator rotationTwo =
                new RotationInterpolator(alphaTwo, cymbal);
        rotationTwo.setSchedulingBounds(view);
        rotationTwo.setTransformAxis(rotate);
        rotationTwo.setMinimumAngle((float) Math.toRadians(-15));
        rotationTwo.setMaximumAngle((float) Math.toRadians(0));
        getSceneGroup().addChild(rotationTwo);

        RotationInterpolator rotationThree =
                new RotationInterpolator(alphaThree, cymbal);
        rotationThree.setSchedulingBounds(view);
        rotationThree.setTransformAxis(rotate);
        rotationThree.setMinimumAngle((float) Math.toRadians(0));
        rotationThree.setMaximumAngle((float) Math.toRadians(10));
        getSceneGroup().addChild(rotationThree);

        RotationInterpolator rotationFour =
                new RotationInterpolator(alphaFour, cymbal);
        rotationFour.setSchedulingBounds(view);
        rotationFour.setTransformAxis(rotate);
        rotationFour.setMinimumAngle((float) Math.toRadians(10));
        rotationFour.setMaximumAngle((float) Math.toRadians(0));
        getSceneGroup().addChild(rotationFour);

    }
    
    /**
     * Let the Drums slowly Rotate for 360 Degrees
     */
    public void turnDrums(){
        BoundingSphere view = new BoundingSphere();

        TransformGroup drums =
                (TransformGroup) getTransformGroups().get("SchlagzeugRoot");
        
        
        Alpha drumsAlpha = new Alpha(1, 3400);
        
        drumsAlpha.setTriggerTime(0);
        drumsAlpha.setStartTime(System.currentTimeMillis()
                - drumsAlpha.getTriggerTime());
        

        RotationInterpolator pedalRotationDown =
                new RotationInterpolator(drumsAlpha, drums);
        pedalRotationDown.setSchedulingBounds(view);
        pedalRotationDown.setMinimumAngle((float) Math.toRadians(0));
        pedalRotationDown.setMaximumAngle((float) Math.toRadians(360));
        getSceneGroup().addChild(pedalRotationDown);
    }

    /**
     * @return the sceneGroup
     */
    public BranchGroup getSceneGroup() {
        return sceneGroup;
    }

    /**
     * @return the scene
     */
    public Scene getScene() {
        return scene;
    }

    /**
     * @return the vrmlLoader
     */
    public VrmlLoader getVrmlLoader() {
        return vrmlLoader;
    }

    /**
     * @return the transformGroups
     */
    public Hashtable getTransformGroups() {
        return transformGroups;
    }

    
}
